﻿using ScFramework.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Triangle : MonoBehaviour
{
    public TriEnum CommenType = TriEnum.Orange;
    public bool AutoRefresh = false;

    public List<TriData> Tris = new List<TriData> { new TriData() };
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        foreach(var x in Tris)
        {
            for(int i = 0; i < 3; i++)
            {

                Gizmos.DrawLine(this.transform.TransformPoint( x.Points[i]),this.transform.TransformPoint( x.Points[(i + 1) % 3]));
            }
        }
    }
    public void RefreshMesh(bool force=true)
    {
        var lists = Tris;
        var trans = transform;
        //   (target as Triangle).GetComponent<MeshFilter>().mesh = new Mesh();
        while (0 < trans.childCount)
        {
            ObjectPool.Recycle(trans.GetChild(0));
        }

        int use = 0;
        for(int i=0;i<lists.Count;i++)
        {
            var x = lists[i];

            List<Vector2> vecs = new List<Vector2>(x.Points);
            if (Vector3.Cross(vecs[1] - vecs[0], vecs[2] - vecs[1]).z > 0)
            {
                var tp = vecs[2];
                vecs[2] = vecs[1];
                vecs[1] = tp;
            }
            MeshFilter filter;
            Mesh mesh = new Mesh();
            if (use == trans.childCount)
            {
                GameObject obj = null;
                if (Application.isPlaying)
                {
                    obj =ResourceManager.Instance.Instantiate("Prefabs/Mesh",trans);

                }
                else
                {
                    obj = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/Mesh"), trans);
                    obj.transform.GetComponent<MeshComp>().Data = null;
                }
                obj.transform.localScale = Vector3.one;
                obj.transform.localPosition = Vector3.zero;
                filter = obj.GetComponent<MeshFilter>();
                use++;
                //    obj.AddComponent(trans.GetComponent<MeshRenderer>);
            }
            else
            {
                trans.GetChild(use).gameObject.SetActive(true);
                filter = trans.GetChild(use++).GetComponent<MeshFilter>();

            }
            var vecs3 = vecs.ConvertAll(s => new Vector3(s.x, s.y, UnityEngine.Random.Range(-10, 10)));
            mesh.vertices = vecs3.ToArray();
            mesh.uv = vecs3.ConvertAll(s => new Vector2(s.x, s.z)).ToArray();
            mesh.triangles = new int[] { 0, 1, 2 };
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
            mesh.RecalculateTangents();
            filter.mesh = mesh;
            if (force || filter.GetComponent<MeshComp>().Tri == null)
            {
                filter.GetComponent<MeshComp>().Tri = x;

            }
            else
            {
                lists[i] = filter.GetComponent<MeshComp>().Tri= filter.GetComponent<MeshComp>().Tri;
            }
/*            if (Main.Instance != null)
            {

                filter.GetComponent<MeshRenderer>().material = Main.Instance.Config.MatDic.Find(s => s.Type == x.Type).Mat;
            }
            else
            {
                filter.GetComponent<MeshRenderer>().material =Resources.Load<Conf>("Config/Conf").MatDic.Find(s => s.Type == x.Type).Mat;
            }*/
        }
        while (use < trans.childCount)
        {
            ObjectPool.Recycle(trans.GetChild(use));
        }
     
    }
}
[Serializable]
public class TriData
{
    public TriEnum Type = TriEnum.Orange;
    public List<Vector2> Points =new List<Vector2> {
new Vector2(-1, 0),
new    Vector2(1, 0),
  new  Vector2(0, 1)};
    public Vector2 Center
    {
        get=>(Points[0]+Points[1]+Points[2])/3;
    }
    public bool ContainPoint(Vector2 v)
    {
        for(int i = 0; i < 3; i++)
        {
            var line = GetLine(i);
            if (Vector3.Cross(line.Item1 - line.Item2, v - line.Item2).z > 0)
            {
                return false;
            }
        }
        return true;
    }
    public bool Equ(TriData eq)
    {
        for(int i = 0; i < 3; i++)
        {
            if (ContainLine(eq.GetLine(i)) == false)
            {
                return false;
            }
        }
        return true;
    }
    public void Normalize()
    {
        if (IsAntiClock() == false)
        {
                var tp =Points[0];
                Points[0] = Points[1];
               Points[1] = tp;
        }
    }
    public TriData ToWorld(Transform trans)
    {

        TriData ans = new TriData();
        ans.Type = Type;
        for (int i = 0; i < 3; i++) ans.Points[i] = trans.TransformPoint(Points[i]);
        return ans;
    }
    public bool IsAntiClock()
    {
        return Vector3.Cross(Points[1] - Points[0], Points[2] - Points[1]).z >= 0;
    }
    public Tuple<Vector2,Vector2>GetLine(int id)
    {
        return new Tuple<Vector2, Vector2>(Points[id%3], Points[(id + 1) % 3]);
    }
    public int GetId(Vector2 down)
    {
        for(int i = 0; i < 3; i++)
        {
            if (Vector2.Dot(down, GetVtr(i)).FloatEqu(0))
            {
                return i;
            }
        }
        throw new Exception();
    }
    public Vector2 GetDownVtr( int id)
    {
        Debug.Assert(IsAntiClock());
        return GetVtr(id).TurnAngle(-Mathf.PI / 2).normalized;
    }
    public Vector2 GetVtr(int id)
    {
        return Points[(id + 1) % 3]- Points[id % 3] ;
    }
    public int  GetLineId(Tuple<Vector2, Vector2> v)
    {
        Debug.Assert(ContainLine(v));
        for(int i = 0; i < 3; i++)
        {
            if (Points[i].VecEqu(v.Item1) && Points[(i + 1) % 3].VecEqu(v.Item2))
            {
                return i;
            }
            if (Points[i].VecEqu(v.Item2) && Points[(i + 1) % 3].VecEqu(v.Item1))
            {
                return i;
            }
        }
        throw new Exception();
    }
    public bool ContainLine(Tuple<Vector2, Vector2> v)
    {
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if (i != j)
                {
                    if (Points[i].VecEqu(v.Item1) && Points[j].VecEqu(v.Item2))
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    public void SetData(TriData d)
    {
        Type = d.Type;
        Points = d.Points;
    }
}

public enum TriEnum
{
    Orange,
    Green,
    Yellow,
    Red,
    Blue
}